//---------------------------------------------------------------------------- // File: CBank.cpp // Class: CBank -- Class Bank // Type: Data Management // Author: Ken Anderson // Date: 5/16/04 // OS dependant: NA // Desc: A class designated to manage data in a bank or a queue. // +The system uses a double-link list for quicker access at the expensive // or more memory. // +The system uses a bottom indexing system, meaning that the bottom of the // bank is refered to as index zero, while a top indexing system references the top as zero. // // Required headers: // 1. CBank.h == Contains common definitions & typedefs. //---------------------------------------------------------------------------- #include "CBank.h" /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: Constructor // Overridden: No // Date: 5/16/4 // Type: Data Management // Permission: NA // Desc: Initializes member variables. // Parameters: None // Return value: None ////////////////////////////////////////////////////////////////////////////////////////////////////// CBank::CBank() { m_pTop_Packet = NULL; m_pTail_Packet = NULL; } /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: Destructor // Overridden: No // Date: 5/16/4 // Type: Data Management // Permission: NA // Desc: Cleans up, destroys memory. // Parameters: None // Return value: None ////////////////////////////////////////////////////////////////////////////////////////////////////// CBank::~CBank(){Purge();} ///////////////////////////////////////////////////// //---------------------/// PRIVATE MEMBERS ///------------------------// ///////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: IsEmpty // Overridden: No // Date: 5/16/4 // Type: Data Management // Permission: Private // Desc: Returns a boolean value, true if the bank is empty and false if it is not. // Parameters: None // Return value: // bool == Returns true or false depending on if the bank is empty. ////////////////////////////////////////////////////////////////////////////////////////////////////// bool CBank::IsEmpty() { //If both top & tail pointers are null return true. if((m_pTail_Packet == NULL) && (m_pTop_Packet == NULL)) return true; //If only one pointer is null, then the list is corrupted and //repair it with BankRepair. if((m_pTail_Packet == NULL) || (m_pTop_Packet == NULL)) BankRepair(); //List is valid, exit return false; } /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: BankRepair // Overridden: No // Date: 5/17/4 // Type: Data Management // Permission: Private // Desc: Repairs the bank's top & tail pointers. // Parameters: None // Return value: None ////////////////////////////////////////////////////////////////////////////////////////////////////// void CBank::BankRepair() { //Locals. PBDP pCurr; //If tail is null, but top is valid if((m_pTail_Packet == NULL) && (m_pTop_Packet != NULL)) { //Set the current to the top of the packet pCurr = m_pTop_Packet; //Find the final packet in the list while(pCurr->pNext != NULL) pCurr = pCurr->pNext; //Assign the tail to the last element. m_pTail_Packet = pCurr; } //If the top is null, but the tail is valid if((m_pTail_Packet != NULL) && (m_pTop_Packet == NULL)) { //Only solution since a bank doesn't use previous pointers //is to force the top to point to the tail, the only valid element. pCurr = m_pTail_Packet; //Cycle back up through the list to the first element. while(pCurr->pPrev != NULL) pCurr = pCurr->pPrev; //Assign the top to the first element. m_pTop_Packet = pCurr; } } /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: ReturnBankElement // Overridden: No // Date: 5/18/4 // Type: Data Management // Permission: Private // Desc: Returns the bank element's address at the specified location or index. // Parameters: // 1) PBDP* hCurrPacket == A handle to the current packet being passed back with the address of the // packet specified in wIndex. // 3) BST bstIndex == A Basic Size Type that is a numeral value that represents the index, element // location within the bank. // Indicies start with a zero base. 0 to (MaxValue - 2) // Indicies starting with zero are elements on the bottom. (BOTTOM INDEXING) // Indicies with a value of MaxValue represents the BANK_INDEX_TOP. // Indicies with a value of MaxValue - 1 represents the BANK_INDEX_TAIL. // Return value: None ////////////////////////////////////////////////////////////////////////////////////////////////////// BANKERR CBank::ReturnBankElement(PBDP* hCurrPacket, BST bstIndex) { //Locals PBDP pCurrPacket=NULL, pPrevPacket=NULL; BST counter = 0; //Exit if the bank is empty if(IsEmpty() == true) return BKERR_EMPTY; //Error: Corrupt bank, one pointer is pointing to a valid element the other is not. if((m_pTop_Packet == NULL) || (m_pTail_Packet == NULL)) BankRepair(); //Repair damage //Searching for the top element if(bstIndex == BANK_INDEX_TOP) { if(hCurrPacket != NULL) *hCurrPacket = m_pTop_Packet; //Top element becomes the current. return BK_OK; } if(bstIndex == BANK_INDEX_TAIL) { if(hCurrPacket != NULL) *hCurrPacket = m_pTail_Packet; //Tail element becomes the current. return BK_OK; } //Set current to the top. pCurrPacket = m_pTail_Packet; //Cycle through the bank upwards until the top is hit //or the counter reaches the specified index. while(pCurrPacket != NULL && counter < bstIndex) { pCurrPacket = pCurrPacket->pPrev; //Get previous value. counter++; //Inc Counter } //If current packet is null then the index was not found and does not exist //so out of range is returned. if(pCurrPacket == NULL) return BKERR_OUTOFRNG; //Return pointers to current packet & previous packet. if(hCurrPacket != NULL) *hCurrPacket = pCurrPacket; return BK_OK; } /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: Scan // Overridden: No // Date: 5/21/4 // Type: Data Management // Permission: Private // Desc: Scans the bank for an element that contains the same properties as listed in // the parameters below. // Parameters: // 1) void* pvData == A pointer to a void data type block of memory to match one in the bank. // 2) Dword dwSize == The size of the block of memory to check against in the bank. // 3) BST& rbstIndex == Returns a value that represents the index of where the element // is located in the bank. // Bottom indexing is used meaning the index starts at zero at the bottom. // Return value: // bool == Returns true if the packet is found in the bank else returns false. ////////////////////////////////////////////////////////////////////////////////////////////////////// bool CBank::Scan(void* pvData, Dword dwSize, BST& rbstIndex) { //Locals BST counter = 0; PBDP pCurrPacket = NULL; //Return zero if the bank is empty. if(IsEmpty() == true) return false; //Error: Corrupt bank, one pointer is pointing to a valid element the other is not. if((m_pTop_Packet == NULL) || (m_pTail_Packet == NULL)) BankRepair(); //Repair damage //Assign current packet to the top. pCurrPacket = m_pTail_Packet; //Loop through the list until the top of the bank is reached. while(pCurrPacket != NULL) { //If the packet data & size match, element found. if( (pCurrPacket->dwSize == dwSize) && (pCurrPacket->pvData == pvData) ) return true; pCurrPacket = pCurrPacket->pPrev; //Fetch next element if(rbstIndex != NULL) rbstIndex += 1; //Inc counter } //Bottom of the bank reached, no elements matched. return false; } ///////////////////////////////////////////////////// //---------------------/// PUBLIC MEMBERS ///------------------------// ///////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: Depth // Overridden: No // Date: 5/16/4 // Type: Data Management // Permission: Public // Desc: Basic pop with no parameters pops a message off the bottom/tail of the message bank. // Parameters: None // Return value: // BST == Returns the Basic Size Type that is a numeral representing // the size, amount of elements, of the bank. ////////////////////////////////////////////////////////////////////////////////////////////////////// BST CBank::Depth() { //Locals BST counter = (BST)0; //Return zero if the bank is empty. if(IsEmpty() == true) return counter; //Error: Corrupt bank, one pointer is pointing to a valid element the other is not. if((m_pTop_Packet == NULL) || (m_pTail_Packet == NULL)) BankRepair(); //Repair damage //Create a temporary packet & set to top. PBDP pCurrPacket = m_pTop_Packet; while(pCurrPacket != NULL) { pCurrPacket = pCurrPacket->pNext; //Fetch next element counter++; //Inc counter. } //Return element count. return counter; } /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: Purge // Overridden: No // Date: 5/23/4 // Type: Data Management // Permission: Public // Desc: Cycles through the bank destroying all elements. // // IMPORTANT NOTE: USING PURGE DESTROYS ALL DATA IN THE BANK BUT DOES NOT CLEAN UP DATA BEING // POINTED TO THROUGH AN ADDRESS IN THE BANK. ANY POINTERS WITHIN THE DATA // BLOCKS SENT TO THE BANK MUST BE DESTROYED FIRST. // Parameters: NONEN // Return value: NONE ////////////////////////////////////////////////////////////////////////////////////////////////////// void CBank::Purge() { //Locals PBDP pTmp = NULL; //Temporarily used to hold next element during element deletion. //Cycle throught the bank from the top. while(m_pTop_Packet != NULL) { pTmp = m_pTop_Packet; //Assign temporary to the top element. m_pTop_Packet = m_pTop_Packet->pNext; //Assign the top element to the next element. SDELETE(pTmp); //Destroy the top or temp element. } m_pTop_Packet = m_pTail_Packet = NULL; } /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: Pop // Overridden: No // Date: 5/16/4 // Type: Data Management // Permission: Public // Desc: Extended pop that will destory the specific element with the index in parameter bstIndex. // Pop will fail if the index is beyond the bank's size. // IMPORTANT NOTE: Confirm that all pointers in the element being popped have already been cleaned up // safely and left with a null condition. Failure to do so could result in left over // resident memory, or pop destroying unathorized memory as there is no null state // present to notify it to stop. // Parameters: // 1) BST bstIndex == A Basic Size Type that is a numeral value that represents the index, element // location within the bank. // Indicies start with a zero base. 0 to (MaxValue - 2) // Indicies starting with zero are elements on the bottom, bottom indexing. // Indicies with a value of MaxValue represents the BANK_INDEX_TOP. // Indicies with a value of MaxValue - 1 represents the BANK_INDEX_TAIL. // Return value: // BANKERR == Returns an error code specific to the bank class. View CBank.h for a list of // error codes. ////////////////////////////////////////////////////////////////////////////////////////////////////// BANKERR CBank::Pop(BST bstIndex) { //Locals PBDP pCurrPacket = NULL, pPrev = NULL, pNext = NULL; BANKERR err = BK_OK; //Find the element specified in bstIndex. //If the tail element is not found or another critical error occurs //return the error. if(FAIL(err = ReturnBankElement(&pCurrPacket, bstIndex))) return err; //Assign previous and next packets. //If at the top or the bottom one of the following will be null. pPrev = pCurrPacket->pPrev; pNext = pCurrPacket->pNext; //Reroute the previous and next elements to point to each other //and to disclude the the element being destroyed. if(pPrev != NULL) pPrev->pNext = pNext; if(pNext != NULL) pNext->pPrev = pPrev; //Reassign the tail and top as needed. if(pPrev == NULL) m_pTop_Packet = pNext; //On top, set top to next. if(pNext == NULL) m_pTail_Packet = pPrev; //On bottom, set to prev. //Clean up data in the current packet. //if(pCurrPacket->pvData != NULL) // delete pCurrPacket->pvData; //Erase Element SDELETE(pCurrPacket); return BK_OK; //Everything is okay. } /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: Pop // Overridden: No // Date: 9/6/4 -- MFM // Type: Data Management // Permission: Public // Desc: Performs a pop of the object in the handle out of the bank. If the object is not found in the // bank, the error returned is out of range. This pop function performs a safety check making // sure the object specified by the handle does exist in the bank before removing it from memory. // // IMPORTANT NOTE: Confirm that all pointers in the element being popped have already been cleaned up // safely and left with a null condition. Failure to do so could result in left over // resident memory, or pop destroying unathorized memory as there is no null state // present to notify it to stop. // Parameters: // 1) void** hCallback == A direct handle to the object in the bank that will be removed. // Object will be checked to confirm it is in the bank. // 2) Dword dwSize == Size of the object to pop off, which will be used in the search. // Return value: // BANKERR == Returns an error code specific to the bank class. View CBank.h for a list of // error codes. ////////////////////////////////////////////////////////////////////////////////////////////////////// BANKERR CBank::Pop(void* hCallback, Dword dwSize) { //Locals PBDP pCurrPacket = NULL, pPrev = NULL, pNext = NULL; //Object found in the bank. if(Exists(hCallback, dwSize) == true) { //Type cast the pointer. pCurrPacket = (PBDP)hCallback; //Assign previous and next packets. //If at the top or the bottom one of the following will be null. pPrev = pCurrPacket->pPrev; pNext = pCurrPacket->pNext; //Reroute the previous and next elements to point to each other //and to disclude the the element being destroyed. if(pPrev != NULL) pPrev->pNext = pNext; if(pNext != NULL) pNext->pPrev = pPrev; //Reassign the tail and top as needed. if(pPrev == NULL) m_pTop_Packet = pNext; //On top, set top to next. if(pNext == NULL) m_pTail_Packet = pPrev; //On bottom, set to prev. //Erase Element SDELETE(pCurrPacket); return BK_OK; } else return BKERR_OUTOFRNG; //Out of Range as object as not found. } /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: Push // Overridden: No // Date: 5/16/4 // Type: Data Management // Permission: Public // Desc: Basic push that pushes a data packet onto the top of the bank. // **Push always inserts elements below the element specified in bstIndex // with the exception of the BANK_INDEX_TOP flag which forces the new element // to the top. // Parameters: // 1) PBDP ppacket == Bank Data Packet to be added on top of the bank. // 2) BST bstIndex == Index or location to insert the Bank Data Packet. // By default will insert at the top of the bank(BANK_INDEX_TOP). // To add an element under the top element, use the index of the top // element. // Return value: // BANKERR == Returns an error code specific to the bank class. View CBank.h for a list of // error codes. ////////////////////////////////////////////////////////////////////////////////////////////////////// BANKERR CBank::Push(PBDP ppacket, BST bstIndex) { //Locals PBDP pCurrPacket = NULL, pPrev = NULL, pNext = NULL; BANKERR err = BK_OK; //Ignore null values. if(ppacket == NULL) return BKERR_NULL; //Find the tail element. //If the tail element is not found or another critical error occurs //return the error. if(FAIL(err = ReturnBankElement(&pCurrPacket, bstIndex))) if(err != BKERR_EMPTY) //Ignore bank empty errors. return err; //Change the assignment if adding an element to the top. //Elements added to the top are placed above the element. if(bstIndex == BANK_INDEX_TOP) { pNext = pCurrPacket; //The top becomes next. pPrev = NULL; //No previous at top. m_pTop_Packet = ppacket; //New element becomes top. } else { if(pCurrPacket != NULL) pNext = pCurrPacket->pNext; //Next element becomes the next inline. pPrev = pCurrPacket; //Current becomes Previous. } //Assign new element to point to previous & next elements. ppacket->pNext = pNext; ppacket->pPrev = pPrev; //Assign elements in the bank to point to the new one. if(pNext != NULL) pNext->pPrev = ppacket; if(pPrev != NULL) pPrev->pNext = ppacket; //Top only condition: assign top to new. if((pPrev == NULL) || bstIndex == BANK_INDEX_TOP) m_pTop_Packet = ppacket; //Set the tail element to the newest element if it is being //added specifically to the top with the BANK_INDEX_TAIL flag //or the bottom of the bank is reached. if((bstIndex == BANK_INDEX_TAIL) || (pCurrPacket == NULL)) m_pTail_Packet = ppacket; //If the tail has not been assigned, assign it to the same element, if(m_pTail_Packet == NULL) m_pTail_Packet = m_pTop_Packet; return BK_OK; } /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: Push // Overridden: No // Date: 5/18/4 // Type: Data Management // Permission: Public // Desc: Basic push that pushes a void pointer and its size into the bank, allowing the // bank to manage memory in creating elements. Returns a pointer of the element // through the handle hAddress. // Parameters: // 1) void* pvData == A pointer to a void block of memory to be added to the bank. // 2) Dword dwSize == Size of the region of memory the pvData occupies. // 3) BST bstIndex == Index or location to insert the block of memory. // By default will insert a the top of the bank(BANK_INDEX_TOP). // 4) PBDP* hAddress == A handle containing the address of the newly created element // block in the bank. // Return value: // BANKERR == Returns an error code specific to the bank class. View CBank.h for a list of // error codes. ////////////////////////////////////////////////////////////////////////////////////////////////////// BANKERR CBank::Push(void* pvData, Dword dwSize, BST bstIndex, PBDP* hAddress) { //Locals PBDP pNewElement; //Allocate memory for the bank data packet. if((pNewElement = new BDP) == NULL) return BKERR_OUTOFMEM; //Out of memory, can't add data to bank. //Assign data to newly created element. pNewElement->dwSize = dwSize; pNewElement->pvData = pvData; pNewElement->pNext = NULL; pNewElement->pPrev = NULL; //Assign the new element's memory address to the handle PBDP //so that it maybe returned. if(hAddress != NULL) *hAddress = pNewElement; return Push(pNewElement, bstIndex); } /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: Replace // Overridden: No // Date: 5/21/4 // Type: Data Management // Permission: Public // Desc: Replaces the packet with the properties listed in the parameters below at // the specified index. // WARNING: MEMORY IN THE PVDATA FIELD IS NOT CLEANED UP DURING THE REPLACE PROCESS. // DATA in the pvdata field should be erased before being replaced. // Parameters: // 1) void *pvData == A pointer to a void data type containing a value that will replace // the data located at the specified index. // 2) Dword dwSize == The size of the void data block that will replace the data located // at the specified index. // 3) BST bstIndex == Index or location of the packet to replace with ppacket. // By default will replace the packet at the top of the bank // (BANK_INDEX_TOP). // Return value: // BANKERR == Returns an error code specific to the bank class. View CBank.h for a list of // error codes. ////////////////////////////////////////////////////////////////////////////////////////////////////// BANKERR CBank::Replace(void *pvData, Dword dwSize, BST bstIndex) { //Locals PBDP pData=NULL; BANKERR err = BK_OK; //Return the current element in the bank at the index location. //Ignore the previous element by setting it to null. if(FAIL(err = ReturnBankElement(&pData, bstIndex))) return err; //Replace the data with the ppacket. pData->dwSize = dwSize; pData->pvData = pvData; return BK_OK; } /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: Replace // Overridden: No // Date: 5/23/4 // Type: Data Management // Permission: Public // Desc: Replaces the packet with ppacket at the specified index. // WARNING: MEMORY IN THE PVDATA FIELD IS NOT CLEANED UP DURING THE REPLACE PROCESS. // DATA in the pvdata field should be erased before being replaced. // Parameters: // 1) PBDP ppacket == Bank Data Packet to replace. // 2) BST bstIndex == Index or location of the packet to replace with ppacket. // By default will replace the packet at the top of the bank // (BANK_INDEX_TOP). // Return value: // BANKERR == Returns an error code specific to the bank class. View CBank.h for a list of // error codes. ////////////////////////////////////////////////////////////////////////////////////////////////////// BANKERR CBank::Replace(PBDP ppacket, BST bstIndex) { return Replace(ppacket->pvData, ppacket->dwSize, bstIndex); } /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: Peek // Overridden: No // Date: 5/23/4 // Type: Data Management // Permission: Public // Desc: Returns a copy of the element in the bank with the index specified. // NOTE: RETURNS A COPY. CLEAN UP WHEN DONE. // Parameters: // 1) BST bstIndex == Index or location of the packet to be copied & returned. // By default will return a copied packet from the top of the bank // (BANK_INDEX_TOP). // Return value: // PBDP == A pointer to a Bank Data Packet that contains a copy of the information // located on the bank. Failure to allocate memory, or other failures return a null // pointer. ////////////////////////////////////////////////////////////////////////////////////////////////////// PBDP CBank::Peek(BST bstIndex) { //Locals PBDP pData=NULL, pCopy=NULL; //Allocate memory for the copy. if((pCopy = new BDP) == NULL) return NULL; //Return null if memory allocation fails. //Return the current element in the bank at the index location. //Ignore the previous element by setting it to null. if(FAIL(ReturnBankElement(&pData, bstIndex))) return NULL; //Copy data from the element to the packet being returned. pCopy->dwSize = pData->dwSize; pCopy->pvData = pData->pvData; pCopy->pNext = NULL; pCopy->pPrev = NULL; //Return copied packet. return pCopy; } /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: Get // Overridden: No // Date: 5/23/4 // Type: Data Management // Permission: Public // Desc: Returns the element in the bank with the index specified removing it from the bank. // Parameters: // 1) BST bstIndex == Index or location of the packet to be creturned. // By default will return a packet from the top of the bank // (BANK_INDEX_TOP). // Return value: // PBDP == A pointer to a Bank Data Packet that contains the information // located on the bank. Failure to allocate memory, or other failures // return a null pointer. ////////////////////////////////////////////////////////////////////////////////////////////////////// PBDP CBank::Get(BST bstIndex) { //Locals PBDP pData=NULL; //Fetch a copy of the data. pData = Peek(bstIndex); //Delete the data off the stack. Pop(bstIndex); //Return copied packet. return pData; } /////////////////////////////////////////////////////////////////////////////////////////////////////// // Class: CBank // Name: Swap // Overridden: No // Date: 5/23/4 // Type: Data Management // Permission: Public // Desc: Swaps two elements on top of the bank. // Parameters: None // Return value: // BANKERR == Returns an error code specific to the bank class. View CBank.h for a list of // error codes. // Will return BK_EMPTY if the bank is empty & can not perform the operation. // BK_OUTOFRNG is returned if only one value in the bank. ////////////////////////////////////////////////////////////////////////////////////////////////////// BANKERR CBank::Swap() { //Locals //pSwap1 is the element on the top. //pSwap2 is the element under pSwap1. PBDP pSwap1 = NULL, pSwap2 = NULL; //Exit if the bank is empty if(IsEmpty() == true) return BKERR_EMPTY; //Error: Corrupt bank, one pointer is pointing to a valid element the other is not. if((m_pTop_Packet == NULL) || (m_pTail_Packet == NULL)) BankRepair(); //Repair damage //Return out of range if only one element is available. if(m_pTop_Packet->pNext == NULL) return BKERR_OUTOFRNG; //Swap the two link list elements. pSwap1 = m_pTop_Packet; //Get the first swap element. pSwap2 = pSwap1->pNext; //Get the second swap element. //Begin swap process. //Swap element one. pSwap1->pPrev = pSwap2; //Top: Point back to bottom. pSwap1->pNext = pSwap2->pNext; //Top: Point forward to bottom's next. //Swap element two. pSwap2->pPrev = m_pTop_Packet; //Bottom: Point back to top of bank. pSwap2->pNext = pSwap1; //Bottom: Point forward to top. //Assign the top to point to the second element, once below the first. m_pTop_Packet = pSwap2; //Assign the tail to the previous element if only two elements. //if(m_pTail_Packet == pNext) m_pTail_Packet = pTop; return BK_OK; }